using muduoDotNet;
using muduoDotNet.Messages;
using Google.Protobuf;

namespace muduoDotNet.Examples
{
    /// <summary>
    /// 基于Protobuf协议的Echo客户端示例
    /// 演示如何使用框架内置的协议编解码功能
    /// </summary>
    public class ProtobufEchoClientExample
    {
        private readonly EventLoop _loop;
        private readonly TcpClient _client;
        private readonly string _clientId;
        private bool _connected = false;
        private int _messageCount = 0;

        public ProtobufEchoClientExample(string serverIp = "127.0.0.1", int serverPort = 8080)
        {
            _loop = new EventLoop();
            _client = new TcpClient(_loop, serverIp, serverPort);
            _clientId = $"client_{Guid.NewGuid().ToString()[..8]}";
            
            // 设置客户端回调
            _client.ConnectionCallback = OnConnection;
            _client.MessageCallback = OnMessage;
            _client.WriteCompleteCallback = OnWriteComplete;
            
            Logger.Info($"Protobuf Echo Client ({_clientId}) will connect to {serverIp}:{serverPort}");
        }

        /// <summary>
        /// 连接建立/断开回调
        /// </summary>
        private void OnConnection(TcpConnection connection)
        {
            if (connection != null && connection.State == TcpConnectionState.Connected)
            {
                _connected = true;
                Logger.Info($"Connected to server: {connection.RemoteEndPoint}");
                
                // 为连接设置protobuf消息回调
                connection.SetProtocolMessageCallback<EchoResponse>(OnEchoResponse);
                connection.SetProtocolMessageCallback<Heartbeat>(OnHeartbeat);
                connection.SetProtocolMessageCallback<StatusMessage>(OnStatusMessage);
                
                // 发送连接信息
                var connectionInfo = new ConnectionInfo
                {
                    ConnectionId = _clientId,
                    RemoteAddress = "127.0.0.1",
                    RemotePort = 0, // 客户端端口由系统分配
                    ConnectTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                    ProtocolVersion = "1.0"
                };
                
                connection.SendProtobufMessage(connectionInfo);
                
                // 发送第一个心跳
                SendHeartbeat(connection);
            }
            else
            {
                _connected = false;
                Logger.Info("Disconnected from server");
            }
        }

        /// <summary>
        /// 原始消息回调（用于处理非protobuf数据）
        /// </summary>
        private void OnMessage(TcpConnection connection, Buffer buffer)
        {
            // 如果有未被协议解析器处理的原始数据，在这里处理
            if (buffer.ReadableBytes > 0)
            {
                var rawData = buffer.RetrieveAllAsString();
                Logger.Warning($"Received unrecognized raw data: {rawData}");
            }
        }

        /// <summary>
        /// 处理Echo响应
        /// </summary>
        private void OnEchoResponse(TcpConnection connection, EchoResponse response)
        {
            Logger.Info($"Received EchoResponse: '{response.Message}' (server: {response.ServerId}, status: {response.StatusCode})");
        }

        /// <summary>
        /// 处理心跳响应
        /// </summary>
        private void OnHeartbeat(TcpConnection connection, Heartbeat heartbeat)
        {
            Logger.Debug($"Received Heartbeat from server (node: {heartbeat.NodeId})");
        }

        /// <summary>
        /// 处理状态消息
        /// </summary>
        private void OnStatusMessage(TcpConnection connection, StatusMessage status)
        {
            var typeStr = status.Type.ToString();
            Logger.Info($"Received StatusMessage: [{typeStr}] {status.Message}");
            
            if (status.Metadata.Count > 0)
            {
                Logger.Debug("Metadata:");
                foreach (var kv in status.Metadata)
                {
                    Logger.Debug($"  {kv.Key} = {kv.Value}");
                }
            }
        }

        /// <summary>
        /// 写完成回调
        /// </summary>
        private void OnWriteComplete(TcpConnection connection)
        {
            Logger.Debug("Write completed");
        }

        /// <summary>
        /// 发送Echo请求
        /// </summary>
        private void SendEchoRequest(TcpConnection connection, string message)
        {
            var request = new EchoRequest
            {
                Message = message,
                Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                ClientId = _clientId
            };
            
            connection.SendProtobufMessage(request);
            _messageCount++;
            Logger.Info($"Sent EchoRequest #{_messageCount}: '{message}'");
        }

        /// <summary>
        /// 发送心跳
        /// </summary>
        private void SendHeartbeat(TcpConnection connection)
        {
            var heartbeat = new Heartbeat
            {
                Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                NodeId = _clientId
            };
            
            connection.SendProtobufMessage(heartbeat);
            Logger.Debug("Sent Heartbeat");
        }

        /// <summary>
        /// 发送状态消息
        /// </summary>
        private void SendStatusMessage(TcpConnection connection, string message, StatusMessage.Types.StatusType type = StatusMessage.Types.StatusType.Info)
        {
            var status = new StatusMessage
            {
                Type = type,
                Message = message,
                Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
            };
            status.Metadata.Add("client_id", _clientId);
            status.Metadata.Add("message_count", _messageCount.ToString());
            
            connection.SendProtobufMessage(status);
            Logger.Info($"Sent StatusMessage: [{type}] {message}");
        }

        /// <summary>
        /// 发送数据包
        /// </summary>
        private void SendDataPacket(TcpConnection connection, string dataType, byte[] payload)
        {
            var packet = new DataPacket
            {
                DataType = dataType,
                Payload = Google.Protobuf.ByteString.CopyFrom(payload),
                SequenceNumber = _messageCount,
                Checksum = CalculateChecksum(payload)
            };
            packet.Headers.Add("client_id", _clientId);
            packet.Headers.Add("timestamp", DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString());
            
            connection.SendProtobufMessage(packet);
            Logger.Info($"Sent DataPacket: type={dataType}, size={payload.Length} bytes");
        }

        /// <summary>
        /// 计算简单校验和
        /// </summary>
        private string CalculateChecksum(byte[] data)
        {
            uint checksum = 0;
            foreach (byte b in data)
            {
                checksum += b;
            }
            return checksum.ToString("X8");
        }

        /// <summary>
        /// 连接到服务器
        /// </summary>
        public void Connect()
        {
            Logger.Info("Connecting to server...");
            _client.Connect();
        }

        /// <summary>
        /// 断开连接
        /// </summary>
        public void Disconnect()
        {
            if (_connected && _client.Connection != null)
            {
                var disconnectRequest = new DisconnectRequest
                {
                    ConnectionId = _clientId,
                    Reason = "Client initiated disconnect",
                    Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
                };
                
                _client.Connection.SendProtobufMessage(disconnectRequest);
                Thread.Sleep(100); // 给消息一点发送时间
            }
            
            _client.Disconnect();
            _loop.Stop();
        }

        /// <summary>
        /// 运行客户端
        /// </summary>
        public void Run()
        {
            Connect();

            // 在后台线程运行事件循环
            var loopTask = Task.Run(() =>
            {
                try
                {
                    _loop.Start();
                }
                catch (Exception ex)
                {
                    Logger.Error("Event loop error", ex);
                }
            });

            Logger.Info("Press keys to interact:");
            Logger.Info("  'e' - Send echo message");
            Logger.Info("  'h' - Send heartbeat");
            Logger.Info("  's' - Send status message");
            Logger.Info("  'd' - Send data packet");
            Logger.Info("  'i' - Send connection info");
            Logger.Info("  'q' - Quit");

            // 主线程处理用户输入
            while (true)
            {
                var key = Console.ReadKey(true);
                
                if (!_connected || _client.Connection == null)
                {
                    if (key.KeyChar == 'q' || key.KeyChar == 'Q')
                        break;
                    
                    Logger.Warning("Not connected to server!");
                    continue;
                }

                switch (key.KeyChar)
                {
                    case 'e':
                    case 'E':
                        SendEchoRequest(_client.Connection, $"Hello from {_clientId} at {DateTime.Now:HH:mm:ss}");
                        break;
                        
                    case 'h':
                    case 'H':
                        SendHeartbeat(_client.Connection);
                        break;
                        
                    case 's':
                    case 'S':
                        SendStatusMessage(_client.Connection, $"Client {_clientId} is running normally");
                        break;
                        
                    case 'd':
                    case 'D':
                        var testData = System.Text.Encoding.UTF8.GetBytes($"Test data from {_clientId}");
                        SendDataPacket(_client.Connection, "text/plain", testData);
                        break;
                        
                    case 'i':
                    case 'I':
                        var connInfo = new ConnectionInfo
                        {
                            ConnectionId = _clientId,
                            RemoteAddress = _client.Connection.RemoteEndPoint?.ToString() ?? "unknown",
                            RemotePort = 8080,
                            ConnectTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                            ProtocolVersion = "1.0"
                        };
                        _client.Connection.SendProtobufMessage(connInfo);
                        Logger.Info("Sent ConnectionInfo");
                        break;
                        
                    case 'q':
                    case 'Q':
                        Disconnect();
                        loopTask.Wait(5000);
                        return;
                }
            }
        }

        /// <summary>
        /// 示例运行方法
        /// </summary>
        public static void RunExample()
        {
            try
            {
                var client = new ProtobufEchoClientExample();
                client.Run();
            }
            catch (Exception ex)
            {
                Logger.Error("Client error", ex);
            }
        }
    }
}